package com.reflect;

import com.exception.UtilException;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

public class ReflectUtil {
    private static final WeakHashMap<Class<?>, List<Field>> FIELDS_CACHE = new WeakHashMap();

    public static List<Field> getFieldList(Class<?> clazz) throws SecurityException {
        List<Field> fieldList = (List) FIELDS_CACHE.get(clazz);
        if (fieldList == null) {
            fieldList = getFieldListDirectly(clazz, true);
            FIELDS_CACHE.put(clazz, fieldList);
        }

        return fieldList;
    }

    public static List<Field> getFieldListDirectly(Class<?> clazz, boolean withSuperClassFields) throws SecurityException {
        List<Field> result = new ArrayList();

        for (Class searchType = clazz; searchType != null; searchType = withSuperClassFields ? searchType.getSuperclass() : null) {
            result.addAll(Arrays.asList(searchType.getDeclaredFields()));
        }

        return result;
    }

    public static Object getFieldValue(Object obj, Field field) {
        if (null == field) {
            return null;
        } else {
            if (obj instanceof Class) {
                obj = null;
            }

            setAccessible(field);

            try {
                Object o = field.get(obj);
                if (Objects.isNull(o)) {
                    if (isFieldCollectionOrMapType(field)) {
                        return new ArrayList<>();
                    }
                }

                return o;
            } catch (IllegalAccessException var3) {
                throw new UtilException("IllegalAccess for " + field.getDeclaringClass() + "." + field.getName(), var3);
            }
        }
    }

    public static <T extends AccessibleObject> T setAccessible(T accessibleObject) {
        if (null != accessibleObject && !accessibleObject.isAccessible()) {
            accessibleObject.setAccessible(true);
        }

        return accessibleObject;
    }

    // 检查一个Class对象是否是集合类型（包括Map）
    public static boolean isCollectionOrMapType(Class<?> clazz) {
        return Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz);
    }

    // 检查一个Field是否是集合或Map类型的属性
    public static boolean isFieldCollectionOrMapType(Field field) {
        // 获取字段的Class对象
        Class<?> fieldType = field.getType();

        // 检查字段类型是否是集合或Map类型
        return isCollectionOrMapType(fieldType);
    }

    /**
     * 反射获取实例
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> T newInstance(Class<T> t) {
        try {
            T t1 = t.newInstance();
            return t1;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 反射获取实例
     *
     * @param className
     * @param <T>
     * @return
     */
    public static <T> T newInstanceParam(Class... className) {
        try {
            Constructor<T> constructor = className[0].getConstructor(Class.class);
            T instance = constructor.newInstance(className[1]);
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
